<?php
class Engine_Acl_Xml extends Zend_Acl
{
	public function __construct($configXml = null) {
		if (!empty($configXml)) {
			list($roles, $resources) = simplexml_load_file($configXml)->children();

			$this->parseRoles($roles);
			$this->parseResources($resources);
		}
	}

    protected function XmlGetAttributes($xml, $cloneAttributes = null) {
    	if (
    		   (!empty($cloneAttributes) && count(get_object_vars($cloneAttributes)))
    		|| (!empty($xml) && count($xml->attributes()))
    	) {
    		$element = !empty($cloneAttributes) ? clone $cloneAttributes : new stdClass();

    		if (!empty($xml) && count($xml->attributes())) {
	    		foreach($xml->attributes() as $attributeName => $attribute) {
					$element->$attributeName = (string) $attribute;
				}
    		}

			return $element;
    	}

    	return null;
	}

    protected function XmlGetAttributesAsArray($xml) {
   		$attributes = array();

   		foreach($xml->attributes() as $attributeName => $attribute) {
			$attributes[$attributeName] = (string) $attribute;
		}

		return $attributes;
	}

	protected function XmlGetElements($xml, $cloneElement = null) {
		$element = !empty($cloneElement) ? clone $cloneElement : new stdClass();

		if (!empty($xml)) {
			foreach($xml->children() as $name => $value) {
	   			$element->$name = $this->XmlGetAttributes($value);
			}
		}

		return $element;
	}

	protected function XmlGetElementsAsArray($xml, $cloneElements = null) {
		$elements = array();

		if (!empty($xml)) {
			foreach($xml->children() as $childName => $child) {
				$elements[$childName] = $this->XmlGetAttributesAsArray($child);
			}
		}

		return $elements;
	}

	protected function parseRoles($xml, $xmlName = null)
    {
    	foreach ($xml as $roleName => $role) {
			$this->addRole(new Zend_Acl_Role($roleName), $xmlName);

			$this->parseRoles($role, $roleName);
        }

        return $this;
    }

    protected function parseResources($xml, $parentName = null)
    {
    	$chains = (array) $xml->chains;
    	foreach($chains as $resourceName => $resource) {
    		$chainName = $parentName ? $parentName . '-' . $resourceName : $resourceName;

    		$this->add(new Zend_Acl_Resource($chainName), $parentName);

    		if (isset($resource->deny)) {
    			foreach ($resource->deny->children() as $denyName => $deny) {
	    			$this->deny($denyName, $chainName, array_keys($this->XmlGetElementsAsArray($deny)));
    			}
    		}

    		if (isset($resource->allow)) {
    			foreach ($resource->allow->children() as $allowName => $allow) {
	    			$this->allow($allowName, $chainName, array_keys($this->XmlGetElementsAsArray($allow)));
    			}
    		}

    		$this->parseResources($resource, $chainName);
    	}

    	return $this;
    }
}